home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS19.ADF / BasicGadgets / Gadgets.DOC < prev    next >
Text File  |  1989-01-27  |  20KB  |  529 lines

  1.  
  2.  
  3.  
  4.  
  5.                                            Catley,Basic Gadgets,Page 1
  6.  
  7.  
  8.      As I'm sure you're aware, gadgets are those little boxes
  9. containing a word or two, or some type of symbol, which appear in
  10. windows and invite you to click on them to cause some predetermined
  11. event to occur.  Unfortunately, Amiga Basic contains no built-in
  12. functions for drawing or checking gadgets.  However, it is a
  13. relatively easy task to draw and check your own gadgets, and that's
  14. what we're going to look at!  Not only will we see how to do it, but
  15. we'll also see how to do all this from three subprograms that may be
  16. merged into any program which requires them.  You will, in effect,
  17. create your own gadget functions!
  18.  
  19. A Simple Gadget
  20.      The simplest form of gadget is just a box with a word in it.  For
  21. example:
  22.  
  23.      CLS:LINE (36,20)-(92,36),1,b:LOCATE 4,6:PRINT "Gadget"
  24.  
  25.      From a purely functional point of view, there is nothing wrong
  26. with this gadget, but you will probably prefer one that is a little
  27. more pleasing to the eye.  However, there is an important lesson to be
  28. learned from this simple gadget!  Choosing the gadget coordinates!
  29.      The first thing to do is to decide on the location of the text
  30. which will appear within the gadget, and then choose the appropriate
  31. coordinates for the box itself.  In the example above, the box is
  32. drawn four pixels, or half a character wider and higher than the text
  33. itself.  You may, of course, draw your box any distance from the text
  34. you decide, but if it is too big it will look a little odd!  The most
  35. important thing to remember is that text is, for the most part, drawn
  36. at a specific row and column location, and the box should surround the
  37. text evenly.
  38.  
  39. A Prettier Gadget
  40.      Okay, let's see what we can do to make this gadget a little nicer
  41. to look at; something we'd like to have in our programs!  How about if
  42. we make the box solid and then outline it with a contrasting color?
  43. While we're at it, let's insert an inner outline, and place a "shadow"
  44. on the right and lower sides!  Try the following program to see what
  45. it looks like:
  46.  
  47.      LINE (36,20)-(92,36),1,bf
  48.      LINE (36,20)-(92,36),3,b
  49.      LINE (38,22)-(90,34),3,b
  50.      LINE (93,21)-(93,37),2
  51.      LINE (93,37)-(37,37),2
  52.      COLOR 3:LOCATE 4,6:PRINT "Gadget"
  53.  
  54.      If more than one gadget is present at the same time, we can even
  55. use different colors; how about green for a "Yes" gadget, and red for
  56. a "No" gadget?
  57.      Please note that the rest of our discussion will be based on
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.                                            Catley,Basic Gadgets,Page 2
  72.  
  73.  
  74. gadgets of the "prettier type" described above.  Feel free to
  75. establish your own design, but it will also become necessary for you
  76. to make the appropriate changes through-out the remainder of our
  77. discussion!
  78.  
  79. The Components of a Gadget
  80.      By now it should be pretty obvious that to draw each gadget
  81. separately, using the code shown above, would be very cumbersome and a
  82. very poor approach.  This is the perfect situation in which to use a
  83. subroutine.  But we're going one step further, and use a subprogram!
  84. The two big reasons for this are that subprograms are a lot more
  85. independent (very important when they will be used in many programs),
  86. and they can be used in a similar fashion to other functions, i.e.
  87. "name parameters"; and this makes the program easier to read and less
  88. complicated.
  89.      Now, what information about each gadget is our subprogram, (let's
  90. name it "DrawGdgts"), going to need?  Well, for starters, it will need
  91. the coordinates of the upper left-hand corner and either the length
  92. and height in pixels, or the coordinates of the lower right-hand
  93. corner.  We'll use the former, it's easier!  Also, we're going to need
  94. the color of the gadget's background, the color of the border and
  95. contents, the color of the "shadow", and finally, the text that is to
  96. be inserted in the gadget.  That's eight different pieces of
  97. information!
  98.      The most obvious way of handling this is to pass all eight pieces
  99. of information to "DrawGdgts" each time we want to draw a gadget.
  100. Using our earlier example, we'd have:
  101.  
  102.      DrawGdgts 36,20,56,16,1,3,2,"Gadget"
  103.  
  104.      While there is nothing particularly bad about this approach, its
  105. biggest disadvantage is that each gadget must be drawn individually;
  106. we cannot specify a range of gadgets to draw.
  107. This is not terribly important when drawing gadgets (unless you have a
  108. lot of them on the screen at once), but it does take on some
  109. significance when checking which gadget has been selected.  Thus, it
  110. becomes important to be able to specify a range of gadgets to be drawn
  111. or checked - which is why we called the subprogram "DrawGdgts" rather
  112. than "DrawGdgt"!
  113.      Needless to say, given this requirement, the information about
  114. the gadgets must be stored in an array; and since we have both numeric
  115. and string data, we'll actually need two arrays.  This automatically
  116. means the need to DIMension two arrays, and to provide a series of
  117. DATA statements which describe the gadgets.
  118.      This might be done as follows:
  119.  
  120.      NumGdgts=4:DIM Gdgts(NumGdgts-1,6),GdgtTxt$(NumGdgts-1)
  121.  
  122.      The following points are of interest:
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.                                            Catley,Basic Gadgets,Page 3
  138.  
  139.  
  140.      -A variable (NumGdgts) is used to specify the actual number of
  141.       gadgets that will be used.  As we add or delete gadgets to our
  142.       programs, we only have to change the value of one variable
  143.       rather than searching through the entire program for every
  144.       reference to the number of gadgets.
  145.  
  146.      -The "Gdgts" array is two-dimensional; one seven position entry
  147.       for each gadget.
  148.  
  149.      -Remember that arrays start at entry zero, so they are
  150.       dimensioned to the maximum number less one.
  151.  
  152.      The associated DATA statements would look something like:
  153.  
  154.      DATA 36, 20, 56, 16, 1, 3, 2, "Gadget"
  155.  
  156.      In other words, it contains the same eight pieces of information
  157. we've already been discussing!  One important point must be made here,
  158. just in case it has not become obvious!  Since we will be drawing and
  159. checking our gadgets in ranges, gadgets that will appear on the screen
  160. at the same time, must be grouped together in the DATA statements.
  161.  
  162. Saving the Gadget's Components
  163.      All of this brings us to the first of our three subprograms, 
  164. creating the arrays from the DATA statements.  Let's call this
  165. subprogram "BldGdgts".  Now, what information is "BldGdgts" going to
  166. need to perform its defined function of building the two gadget
  167. arrays?  Well, it's going to need to know the total number of gadgets,
  168. and the names of the two arrays.  We'll pass all three pieces of
  169. information as parameters; we could use the SHARED statement, but
  170. while we'll remove the need for parameters, we would be forced into
  171. using the same names in every program, and that might not be what we
  172. really want.  So, we'll invoke our "BldGdgts" subprogram with one of
  173. two statements types:
  174.  
  175.      CALL BldGdgts (NumGdgts,Gdgts(),GdgtTxt$())
  176.  
  177.      or
  178.  
  179.      BldGdgts NumGdgts,Gdgts(),GdgTxt$
  180.  
  181.      Either form is correct and the choice is strictly a personal one.
  182. Note how the arrays are specified.  The () is required for Basic to
  183. know it is an array being passed and not a variable.
  184.      Look at Listing #1 and then type it in.  This is our "BldGdgts"
  185. subprogram; it is a pretty straight-forward use of the READ statement
  186. to extract values from DATA statements and place them in arrays.  Note
  187. that while the specified parameters must be in the same sequence, they
  188. do not need the same names, and that variable names are unique within
  189. a subprogram; i.e. "x" in a subprogram is a different variable from
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.                                            Catley,Basic Gadgets,Page 4
  204.  
  205.  
  206. "x" in a main program.
  207.      Since we will eventually be combining the other two subprograms
  208. with "BldGdgts", pick an appropriate name to save it as!  How about
  209. "Gadgets"?  And remember to save it with the ",A" option; for example:
  210. SAVE "Gadgets",A
  211.      This will allow the code to be merged in with other programs at a
  212. later time.  N.B. You must use an immediate command to do this, the
  213. Project Save menu item cannot be used, at least not for the first
  214. save.
  215.  
  216. Drawing the Gadgets
  217.      All of the array information is now stored in arrays, and the
  218. time has come to use "DrawGdgts".  To do its job, this subprogram
  219. needs to know the starting and ending gadgets to be drawn, and the
  220. name of the arrays containing the gadget data.  Thus, we might use
  221.  
  222.      CALL DrawGdgts (2,5,Gdgts(),GdgtTxt$())
  223.  
  224. to draw gadgets three through six from the arrays; (remember, the
  225. first entry in an array is entry zero).
  226.      Now, "DrawGdgts" itself will set up a loop, and for each gadget
  227. to be drawn, it will:
  228.  
  229.      -extract the necessary data from the array, (not strictly
  230.       necessary, but it allows Basic to make the array calculation
  231.       only once, and it also allows shorter, more usable names to be
  232.       applied to the values)
  233.  
  234.      -draw the gadget in much the same fashion as we did earlier
  235.  
  236.      -print the text in the gadget after calculating the starting row
  237.       and column
  238.  
  239.      Listing #2 shows the "DrawGdgts" subprogram.  It also shows
  240. something new!  The inner outline, text and shadow are only drawn if
  241. the "shadow" color is greater than -1 (or is a valid palette number)!
  242. This minor extension allows us to handle another type of gadget very
  243. easily.
  244.      Up to this point we've been discussing "Yes/No" type gadgets
  245. which will "flash" when clicked on, and which are used simply to
  246. indicate the user's choices.  Another type of gadget is used for data
  247. entry purposes.  For example, in a requester, a user clicks in a box
  248. to indicate some data will be entered.  The box reverses its outline
  249. and interior colors and all is ready for some data to be entered.
  250.      Since this type of gadget will not use a "shadow", we can use
  251. this field to indicate the type of gadget by using an illegal palette
  252. number.  So, if we desire this form of gadget, we set the 
  253. "shadow" color to -1 and everything will be taken care of
  254. automatically!
  255.      Back to "DrawGdgts"; if a -1 is detected as the shadow color,
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.                                            Catley,Basic Gadgets,Page 5
  270.  
  271.  
  272. then only the box and its outline are drawn.  The inner outline and
  273. the text are ignored.
  274.      Now, LOAD "Gadgets" (or whatever you called it) and extend it by
  275. adding Listing #2 to the end, and then save it again.  The ",A" should
  276. not be necessary this time, and the Project Menu save  item may also
  277. be used.  Once saved with the ",A", all future saves (or replaces)
  278. will automatically use the ASCII format.
  279.  
  280. Which Gadget was Clicked?
  281.      Our third subprogram, "GetGdgt" is also our most complicated!  So
  282. before looking at how it works, let's review how 
  283. the mouse might be used to check for a simple gadget being clicked.
  284. Remember, MOUSE(0) returns a zero value until the left button is
  285. pressed when MOUSE(1) returns the x coordinate of the mouse pointer,
  286. and MOUSE(2) returns the y coordinate.  The following sample program
  287. draws a simple gadget, and will not quit      
  288. until you click in the gadget.  Try it!
  289.  
  290.      LINE (36,28)-(92,42),1,B    'Draw Gadget
  291.      LOCATE 5,7:PRINT"Quit"      'Insert Text 
  292.      Ok=0                        'Set Flag=0
  293.      WHILE Ok=0                  'Loop till flag not zero
  294.        WHILE MOUSE(0)=0:WEND     'Wait for click
  295.        x=MOUSE(1):y=MOUSE(2)     'Pick up x & y coordinates
  296.        IF x>36 AND x<92 THEN     'Check x coordinates 
  297.          IF y>28 AND Y<42 THEN   'Check y coordinates
  298.            Ok=1                  'Set flag=1 if in gadget
  299.          END IF
  300.        END IF
  301.      WEND
  302.      LOCATE 1,1:PRINT"You did it!"
  303.      END
  304.  
  305.      The above is pretty straight forward, and once you understand it,
  306. "GetGdgt" will be that much easier to follow.
  307.      To do its job, "GetGdgt" (Listing #3) needs to know the range of
  308. gadgets to be checked, the names of the gadget arrays, and to have a
  309. means of letting the caller know which gadget was clicked in.  The
  310. latter may be handled with a variable that is set to the relative
  311. number of the gadget clicked in, within the given range.  This being
  312. the case,
  313.  
  314.      CALL GetGdgt (2,5,Gdgts(),GdgtTxt$(),gdgt)
  315.  
  316. may be used to determine which gadget, if any, has been clicked.  In
  317. this example, "gdgt" will return 0-4 depending on whether the click
  318. was outside all the gadgets, or was in one of gadgets 3, 4, 5, or 6
  319. respectively.  If "gdgt" comes back as zero, we'll almost certainly
  320. want to loop back and issue the call again.  The following is an
  321. example of how "GetGdgt" might actually be used in many situations:
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.                                            Catley,Basic Gadgets,Page 6
  336.  
  337.  
  338.  
  339.      gdgt=0
  340.      WHILE gdgt=0
  341.        CALL GetGdgt (2,5,Gdgts(),GdgtTxt$(),gdgt)
  342.      WEND
  343.      ON gdgt GOTO Rtn3,Rtn4,Rtn5,Rtn6
  344.  
  345.      The obvious question right now is "Why can't GetGdgt be written
  346. to wait for a click in one of the specified gadgets?"  The answer, for
  347. now, is "Flexibility".  We'll discuss a more practical reason later!
  348.      Beside the five parameters, "GetGdgt" also shares three variables
  349. with the main program.  All are conveniences for the main program; two
  350. pass back the actual x and y coordinates selected, and the third is
  351. simply an indicator that a valid gadget was, indeed, selected.  The
  352. first two are useful when the program needs to know where the pointer
  353. was in the gadget when it was clicked, while the third can be useful
  354. if the program is waiting on more events than just a gadget being
  355. selected.
  356.      Anyway, once "GetGdgt" is called, it waits for a click, sets
  357. variables and picks up the x and y coordinates of the pointer.  It
  358. then loops through the specified range of gadgets to see if any of
  359. them were clicked.  If one was, the gadget is drawn in its opposite
  360. colors (starting the "flash"), the relative number of the gadget
  361. within the specified range is calculated and set, and the loop is
  362. terminated.  At this point, the subprogram waits for the left button
  363. to be released, when it redraws the gadget in its usual colors, (if
  364. the gadget has been selected and the shadow color is greater than -1
  365. and thereby ending the flash).  Before returning to the main program,
  366. the cursor is relocated to its original position.  (The need for this
  367. last function is not that obvious, but I found it the hard way when
  368. trying to combine user input and gadget selection!)
  369.      The listing of "GetGdgt" may look a little complicated, but it
  370. really isn't.  It's just the example we looked at earlier with a few
  371. bells and whistles thrown in!
  372.      It's now time to add "GetGdgt" to "Gadgets".  Load "Gadgets" and
  373. extend it with Listing #3 and save the entire thing.  You could have
  374. saved each of the three subprograms separately if you wished, but
  375. since the chance of one being used without the other is very slim, it
  376. makes more sense to combine them into one program unit.
  377.  
  378. Let's Try Them Out
  379.      After all that effort we'd better make sure they work correctly!
  380. Listing #4 shows a sample program which exercises all three
  381. subprograms.  Enter it as shown, and then click in the Basic Output
  382. Window and enter the immediate command:  MERGE "Gadgets" (or whatever
  383. you called the subprograms).
  384.      The three subprograms should be appended to Listing #4 in your
  385. Edit Window.  If you receive a "Bad File Mode" error message you
  386. probably forgot to use the ",A" option when you originally saved
  387. "BldGdgts".  No problem!  Just save Listing #4, load "Gadgets" again
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.                                            Catley,Basic Gadgets,Page 7
  402.  
  403.  
  404. and then resave it with the ",A" option; (use the immediate command:
  405. SAVE "Gadgets",A), reload Listing #4 and then issue the MERGE again.
  406. Once you have them combined, save the entire program as, say,
  407. "GdgtDemo"; (no need to use the ",A" option now).
  408.      If you look at Listing #4, it wont be too long before you notice
  409. two things that are different from what we have discussed so far.
  410. First, there is a gadget with a shadow color of -2, and we are using a
  411. completely different method of waiting for the mouse click!
  412.      The former is easy, it just gives us a third type of gadget
  413. without any need to modify the gadget subprograms.  This gadget will
  414. not change at all when it is clicked in.  A useful option when
  415. selecting an item from a list to obtain further information in a
  416. separate window.
  417.      The second is a little more involved.  Rather than use the method
  418. of checking the mouse described above, we set up a mouse event
  419. trapping routine, (ON MOUSE GOSUB GetMouse); turn it on, (MOUSE ON);
  420. and then, when it's time to wait for the click, we go to SLEEP until
  421. the user clicks the button.  At this point, control automatically
  422. passes to the "GetMouse" routine which simply invokes "GetGdgt".  The
  423. RETURN results in control being passed back to the statement
  424. immediately following the one that was being executed when the "mouse
  425. event" occurred.  In our case, this is the WEND following the SLEEP.
  426. Now, if "gdgt" is still zero, the program goes right back to SLEEP; if
  427. it is non-zero, it responds appropriately.  In other words, we are
  428. waiting for the click, via the SLEEP statement, outside of the
  429. "GetGdgt" routine.
  430.      Why is this an important option?  Well, assume you have a program
  431. which puts up a "Yes/No" requester, and then goes to "GetGdgt" and
  432. dutifully waits at the WHILE MOUSE(0) statement.  Meanwhile, the user
  433. scratches his/her head and decides to use the help menu that you have
  434. thoughtfully provided, and at the bottom of the help window, lo and
  435. behold, is an "OK" gadget.  The result of this is that when the help
  436. routine tries to go to "GetGdgt", the program crashes with an error
  437. message informing you that a subprogram cannot be used by two users at
  438. the same time! It is, therefore, important to wait outside of the
  439. "GetGdgt" subprogram!  SLEEP is used because it does not require any
  440. CPU cycles (unlike WHILE MOUSE(0)=0:WEND) and this is very important
  441. in a multitasking machine such as the Amiga.  SLEEP is also useful
  442. when you're waiting for one of several events to occur.  Just set up
  443. the event traps and go to SLEEP; there is no need to establish a loop
  444. which is constantly checking on all the events you are waiting on!
  445.      All this is not to say that polling (WHILE MOUSE(0)=0:WEND)
  446. should never be used.  Event traps are just an alternate (but probably
  447. better) method, which involves a little more programming, but which
  448. offers a number of advantages.
  449.      We got side tracked, back to our "GdgtDemo" program!  Once you've
  450. entered Listing #4, MERGEd in the "Gadgets" subprograms, and saved it;
  451. RUN it.  The screen will show a number of gadgets examples in the
  452. lower portion, and will have two "real" gadgets at the top, "More" and
  453. "Quit".  If you click in any of the example gadgets, you'll receive a
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.                                            Catley,Basic Gadgets,Page 8
  468.  
  469.  
  470. message telling you which one you clicked.  If you select "More",
  471. you'll receive a second screen of example gadgets, with "Repeat" and
  472. "Quit" gadgets at the top.  As you might expect, "Repeat" returns you
  473. to the first set of examples, and "Quit" terminates the program, as it
  474. does on the first screen.
  475.      Well, you are now an expert at creating and using your own custom
  476. gadgets from within Amiga Basic!  Use them well and spruce up those
  477. programs! 
  478.  
  479.   
  480.      
  481.  
  482.  
  483.         
  484.  
  485.  
  486.  
  487.  
  488.  
  489.  
  490.  
  491.  
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.